package commDao

import (
	"errors"
	"github.com/TarsCloud/TarsGo/tars"
	"gorm.io/gorm/logger"
	"reflect"
	"runtime/debug"
	"xxgame.com/CommApp/Util/goroutine"
	"xxgame.com/CommApp/Util/log"
)

// 通用持久化对象接口
type CommPstEntityIF interface {
	Get(key string, def interface{}) interface{}
	Set(key string, val interface{})
	Delete(key string)
	Load(params... interface{}) error
	Save() error
	TableName() string
	Remove () error
	OnBorn() error
	MarkDirty()
	ClearDirty()
	IsDirty() bool
	SetLoaded()
	IsLoaded() bool
	Error() error
	SetError(err error)
}

var ErrHaveLoaded = errors.New("pst entity have loaded")

// 通用持久化通用基础类
type CommPstEntityBase struct {
	//CommPstEntityIF
	cond    CommEntityIF
	obj     CommEntityIF
	dao     *CommDao
	dirty   bool
	loaded  bool
	deleted bool
	// RfSelf 模拟多态(this标识当前类的成分，RfSelf表示当前完整对象)
	RfSelf *reflect.Value
	err    error
}

// 创建持久化基类对象
func NewCommPstEntityBase(obj CommEntityIF, dao *CommDao, cond CommEntityIF) *CommPstEntityBase {
	return new(CommPstEntityBase).Init(obj, dao, cond).(*CommPstEntityBase)
}

// 初始化对象属性
func (this *CommPstEntityBase) Init(obj CommEntityIF, dao *CommDao, cond CommEntityIF) interface{} {
	this.cond = cond
	this.obj = obj
	this.dao = dao
	this.dirty = false
	this.loaded = false
	this.deleted = false
	return this
}

// 获取额外数据属性
func (this *CommPstEntityBase) Get(key string, def interface{}) interface{} {
	// 派生类实现具体类
	panic(errors.New("base classes cannot execute this function"))
}

// 设置额外属性数据
func (this *CommPstEntityBase) Set(key string, val interface{}) {
	// 派生类实现具体类
	panic(errors.New("base classes cannot execute this function"))
}

// 删除额外属性数据
func (this *CommPstEntityBase) Delete(key string) {
	// 派生类实现具体类
	panic(errors.New("base classes cannot execute this function"))
}

// 加载数据
// 	不定参数：params...
// 		canAdd:bool	是否在查询为nil时，插入新数据
func (this *CommPstEntityBase) Load(params... interface{}) error {
	if this.IsLoaded() {
		return nil
	}
	canAdd := true
	if 0 < len(params) {
		canAdd = params[0].(bool)
	}
	var err error
	var rowCtn int
	this.obj, err, rowCtn = this.dao.OneById2(this.cond, this.obj)
	curGoid := goroutine.GetID()
	if nil != err {
		// 查不到数据触发OnBorn的调用
		if errors.Is(err, logger.ErrRecordNotFound) {
			if canAdd {
				err = this.OnBorn()
				if nil != err {
					tars.TLOG.Errorf("CommPstEntityBase.Load() OnBorn fail, curGoid=%+v, "+
						"TableName=%+v, err=%+v", curGoid, this.obj.TableName(), err)
					log.PST.Errorf("插入记录失败 CommPstEntityBase.Load(), curGoid=%+v, "+
						"TableName=%+v, cond=%+v, err=%+v", curGoid, this.obj.TableName(),
						this.cond, err.Error())
				} else {
					log.PST.Infof("插入记录成功 CommPstEntityBase.Load(), curGoid=%+v, "+
						"TableName=%+v, cond=%+v", curGoid, this.obj.TableName(), this.cond)
				}
			} else {
				log.PST.Infof("插入记录跳过 CommPstEntityBase.Load()，curGoid=%+v, " +
					"TableName=%+v, cond=%+v, err=%+v", curGoid, this.obj.TableName(),
					this.cond, err.Error())
			}
			return err
		} else {
			tars.TLOG.Errorf("CommPstEntityBase.Load() fail, curGoid=%+v, " +
				"TableName=%+v, err=%+v", curGoid, this.obj.TableName(), err)
			log.PST.Errorf("查询记录失败 CommPstEntityBase.Load(), curGoid=%+v, " +
				"TableName=%+v, cond=%+v, err=%+v", curGoid, this.obj.TableName(), this.cond, err.Error())
			return err
		}
	}
	log.PST.Infof("查询记录成功 CommPstEntityBase.Load(), curGoid=%+v, TableName=%+v, " +
		"rowCtn=%+v, cond=%+v, obj=%+v", curGoid, this.obj.TableName(), rowCtn, this.cond, this.obj)
	this.ClearDirty()
	this.SetLoaded()
	return nil
}

// 执行持久化存储
func (this *CommPstEntityBase) Save() error {
	if !this.IsDirty() {
		return nil
	}
	if this.IsDeleted() {
		return nil
	}
	err := this.dao.Saves(this.cond, this.obj)
	curGoid := goroutine.GetID()
	if nil == err {
		this.ClearDirty()
		log.PST.Infof("持久化成功：curGoid=%+v, tblName=%+v, " +
			"cond=%+v, obj=%+v", curGoid, this.TableName(), this.cond, this.obj)
	} else {
		this.ClearDirty()
		log.PST.Errorf("持久化失败：err=%+v, curGoid=%+v, tblName=%+v, " +
			"cond=%+v, obj=%+v, stack=%+v", err.Error(), curGoid, this.TableName(),
			this.cond, this.obj, string(debug.Stack()))
	}
	return err
}

// 获取数据库表名
func (this *CommPstEntityBase) TableName() string {
	if nil == this.obj {
		return ""
	}
	return this.obj.TableName()
}

// 从数据库中删除（慎用：还未调试）
func (this *CommPstEntityBase) Remove() error {
	ret, err := this.dao.DeleteByWhere(this.cond)
	if ret && nil == err {
		this.SetDeleted()
		return nil
	}
	return err
}

// 响应数据记录出生事件
func (this *CommPstEntityBase) OnBorn() error {
	//return nil // Saves() 函数会判断自动插入，这里就不操作插入
	return this.dao.Add(this.cond)
}

// 标识数据脏
func (this *CommPstEntityBase) MarkDirty() {
	if this.dirty {
		return
	}
	this.dirty = true
}

// 重置脏标识
func (this *CommPstEntityBase) ClearDirty() {
	if !this.dirty {
		return
	}
	this.dirty = false
}

// 是否内存数据脏
func (this *CommPstEntityBase) IsDirty() bool {
	return this.dirty
}

// 加载是否完成
func (this *CommPstEntityBase) IsLoaded() bool {
	return this.loaded
}

// 设置加载是否完成状态
func (this *CommPstEntityBase) SetLoaded() {
	if this.loaded {
		return
	}
	this.loaded = true
}

// 是否从数据库中删除
func (this *CommPstEntityBase) IsDeleted() bool {
	return this.deleted
}

// 设置从数据库中删除状态
func (this *CommPstEntityBase) SetDeleted() {
	if this.deleted {
		return
	}
	this.deleted = true
}

// 获取最后触发的错误 error
func (this *CommPstEntityBase) Error() error {
	return this.err
}

// 设置错误 error
func (this *CommPstEntityBase) SetError(err error) {
	this.err = err
}
